import { SetupContext, defineComponent, ref, watch } from 'vue';
import { MonthViewProps, monthViewProps } from './month-view.props';
import { KeyCode, useEvent } from '../../composition/use-event';
import { useCompare } from '../../composition/use-compare';
import { DateObject, EventItem, MonthTag } from '../../types/common';
import { ScheduleEvent } from '../../types/schedule';
import { DayInCalendar, WeekInCalendar } from '../../types/calendar';
import './month-view.css';
import { defaultNameOfMonths } from '../../types/month';

export default defineComponent({
    name: 'FCalendarMonthView',
    props: monthViewProps,
    emits: [],
    setup(props: MonthViewProps, context: SetupContext) {
        const daysInWeek = ref<string[]>(props.daysInWeek);
        const enableKeyboadNavigate = ref(props.enableKeyboadNavigate);
        const enableMarkCurrent = ref(props.enableMarkCurrent);
        const activeDay = ref<DateObject | null>(props.activeDay);
        const events = ref<ScheduleEvent[]>(props.events);

        const { equal, sameDay } = useCompare();
        const { getKeyCodeFromEvent } = useEvent();

        function fillEvents(dates: WeekInCalendar[], events: EventItem[]) {
            dates.forEach((week: WeekInCalendar) => {
                week.days.forEach((dayItem: DayInCalendar) => {
                    const matchedEvent = events.filter((eventItem: EventItem) => sameDay(eventItem.starts, dayItem.date)) as EventItem[];
                    if (matchedEvent && matchedEvent.length) {
                        dayItem.events = [...matchedEvent];
                    }
                });
            });
            return dates;
        }

        const dates = ref<WeekInCalendar[]>(fillEvents(props.dates, events.value));

        watch(
            () => props.dates,
            () => {
                dates.value = fillEvents(props.dates, events.value);
            }
        );
        watch(
            () => props.activeDay,
            () => {
                activeDay.value = props.activeDay;
            }
        );
        watch(
            () => props.events,
            () => {
                events.value = props.events;
            }
        );

        function isDateSame(day: DateObject) {
            return !!activeDay.value && equal({ year: activeDay.value.year, month: activeDay.value.month, day: activeDay.value.day }, day);
        }

        const dayContainerClass = (currentDay: DayInCalendar, weekIndex: number, dayIndex: number) => {
            const notInCurrentMonth = currentDay.monthTag === MonthTag.previous || currentDay.monthTag === MonthTag.next;
            const classObject = {
                'f-datepicker-no-currmonth': notInCurrentMonth
            } as Record<string, boolean>;
            const className = `d_${weekIndex}_${dayIndex}`;
            classObject[className] = true;
            return classObject;
        };

        const dayClass = (currentDay: DayInCalendar) => {
            const isSelected = currentDay.monthTag === MonthTag.current && isDateSame(currentDay.date);

            const shouldMarkCurrentDay = currentDay.isCurrent && enableMarkCurrent.value;
            const classObject = {
                'f-calendar-month-view-date': true,
                'f-calendar-month-view-selected': isSelected,
                'f-calendar-month-view-current': shouldMarkCurrentDay
            } as Record<string, boolean>;
            return classObject;
        };

        function onClick($event: Event, target: DayInCalendar) {
            $event.stopPropagation();
            context.emit('click', target.date);
        }

        function onKeyDown($event: KeyboardEvent, target: DayInCalendar) {
            const keyCode: number = getKeyCodeFromEvent($event);
            if (keyCode !== KeyCode.tab) {
                $event.preventDefault();

                if (keyCode === KeyCode.enter || keyCode === KeyCode.space) {
                    onClick($event, target);
                } else if (enableKeyboadNavigate.value) {
                    context.emit('keyDown', target.date);
                }
            }
        }

        return () => {
            return (
                <div class="f-calendar-month-view">
                    <table class="f-datepicker-table" cellpadding="0">
                        <thead>
                            <tr>
                                {daysInWeek.value &&
                                    daysInWeek.value.map((day: string) => {
                                        return (
                                            <th scope="col" style="padding: 4px 4px 8px">
                                                {day}
                                            </th>
                                        );
                                    })}
                            </tr>
                        </thead>
                        <tbody>
                            {dates.value &&
                                dates.value.map((week: WeekInCalendar, weekIndex: number) => {
                                    return (
                                        <tr>
                                            {week.days &&
                                                week.days.map((item: DayInCalendar, dayIndex: number) => {
                                                    return (
                                                        <td
                                                            id={`d_${weekIndex}_${dayIndex}`}
                                                            tabindex="0"
                                                            class={dayContainerClass(item, weekIndex, dayIndex)}
                                                            onClick={(payload: MouseEvent) => onClick(payload, item)}
                                                            onKeydown={(payload: KeyboardEvent) => onKeyDown(payload, item)}>
                                                            <div class="f-calendar-month-view-title">
                                                                <div class={dayClass(item)}>{item.date.day}</div>
                                                                <div class="f-calendar-month-view-date-month">
                                                                    {item.date.day === 1 ? defaultNameOfMonths[item.date.month || 1] : ''}
                                                                </div>
                                                            </div>
                                                            {item.events &&
                                                                item.events.length &&
                                                                item.events.map((eventItem: EventItem) => {
                                                                    return (
                                                                        <div class="f-calendar-month-view-event-item">
                                                                            {eventItem.title}
                                                                        </div>
                                                                    );
                                                                })}
                                                        </td>
                                                    );
                                                })}
                                        </tr>
                                    );
                                })}
                        </tbody>
                    </table>
                </div>
            );
        };
    }
});
